// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/audio/sounds/sounds_manager.h"

#include <vector>

#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "media/audio/audio_manager.h"
#include "media/audio/sounds/audio_stream_handler.h"

namespace media {

namespace {

    SoundsManager* g_instance = NULL;
    bool g_initialized_for_testing = false;

    // SoundsManagerImpl ---------------------------------------------------

    class SoundsManagerImpl : public SoundsManager {
    public:
        SoundsManagerImpl() { }
        ~SoundsManagerImpl() override { DCHECK(CalledOnValidThread()); }

        // SoundsManager implementation:
        bool Initialize(SoundKey key, const base::StringPiece& data) override;
        bool Play(SoundKey key) override;
        bool Stop(SoundKey key) override;
        base::TimeDelta GetDuration(SoundKey key) override;

    private:
        AudioStreamHandler* GetHandler(SoundKey key);

        // There's only a handful of sounds, so a vector is sufficient.
        struct StreamEntry {
            SoundKey key;
            std::unique_ptr<AudioStreamHandler> handler;
        };
        std::vector<StreamEntry> handlers_;

        DISALLOW_COPY_AND_ASSIGN(SoundsManagerImpl);
    };

    bool SoundsManagerImpl::Initialize(SoundKey key,
        const base::StringPiece& data)
    {
        if (AudioStreamHandler* handler = GetHandler(key)) {
            DCHECK(handler->IsInitialized());
            return true;
        }

        std::unique_ptr<AudioStreamHandler> handler(new AudioStreamHandler(data));
        if (!handler->IsInitialized()) {
            LOG(WARNING) << "Can't initialize AudioStreamHandler for key=" << key;
            return false;
        }

        handlers_.push_back({ key, std::move(handler) });
        return true;
    }

    bool SoundsManagerImpl::Play(SoundKey key)
    {
        DCHECK(CalledOnValidThread());
        AudioStreamHandler* handler = GetHandler(key);
        return handler && handler->Play();
    }

    bool SoundsManagerImpl::Stop(SoundKey key)
    {
        DCHECK(CalledOnValidThread());
        AudioStreamHandler* handler = GetHandler(key);
        if (!handler)
            return false;
        handler->Stop();
        return true;
    }

    base::TimeDelta SoundsManagerImpl::GetDuration(SoundKey key)
    {
        DCHECK(CalledOnValidThread());
        AudioStreamHandler* handler = GetHandler(key);
        return !handler ? base::TimeDelta() : handler->duration();
    }

    AudioStreamHandler* SoundsManagerImpl::GetHandler(SoundKey key)
    {
        for (auto& entry : handlers_) {
            if (entry.key == key)
                return entry.handler.get();
        }
        return nullptr;
    }

} // namespace

SoundsManager::SoundsManager() { }

SoundsManager::~SoundsManager() { DCHECK(CalledOnValidThread()); }

// static
void SoundsManager::Create()
{
    CHECK(!g_instance || g_initialized_for_testing)
        << "SoundsManager::Create() is called twice";
    if (g_initialized_for_testing)
        return;
    g_instance = new SoundsManagerImpl();
}

// static
void SoundsManager::Shutdown()
{
    CHECK(g_instance) << "SoundsManager::Shutdown() is called "
                      << "without previous call to Create()";
    delete g_instance;
    g_instance = NULL;
}

// static
SoundsManager* SoundsManager::Get()
{
    CHECK(g_instance) << "SoundsManager::Get() is called before Create()";
    return g_instance;
}

// static
void SoundsManager::InitializeForTesting(SoundsManager* manager)
{
    CHECK(!g_instance) << "SoundsManager is already initialized.";
    CHECK(manager);
    g_instance = manager;
    g_initialized_for_testing = true;
}

} // namespace media
